/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.toolkit.shape.impl;

import java.util.ArrayList;
import java.util.ListIterator;

/**
 * TMap project
 * WHO 2004-2005 
 * 
 * @author stl
 */
public class CircularListIterator implements Cloneable {

    public static final int FORWARD =1;
    public static final int BACKWARD =-1;
    
    @SuppressWarnings("unchecked")
	private ArrayList list =null;
    @SuppressWarnings("unchecked")
	private ListIterator lit =null;
    private int direction =FORWARD;
    private int nbSteps =-1;
    private Object currElt;

    @SuppressWarnings("unchecked")
	public CircularListIterator( ArrayList list ) {
        this.list =list;
        reset();
        //iterate();
    }
    
    public Object clone() {
        CircularListIterator clit =new CircularListIterator( list );
        clit.direction =direction;
        clit.nbSteps =nbSteps;
        clit.currElt =currElt;
        
        return clit;
    }
    
    /**
     * Reset the circular list iterator
     *
     */
    public void reset() {
        lit =list.listIterator();
        direction =FORWARD;    
        nbSteps =0;
        currElt =null;
    }
    
    /**
     * @return Returns the direction.
     */
    public int getDirection() {
        return direction;
    }
    
    /**
     * @param direction The direction to set.
     */
    public void setDirection(int direction) {
        this.direction = direction;
        nbSteps =0;
    }

    /**
     * Reverse iterating direction and reset the number of steps
     * @return the new direction
     */
    public int reverseDirection() {
        direction*=-1;
        nbSteps =0;
        
        return direction;
    }
    
    /**
     * Use the number of steps to check if the whole list has been traversed
     * @return true if the whole list has been traversed, false otherwise
     */
    public boolean hasTraversedAllElements() {
        return nbSteps >= list.size();
    }
    
    /**
     * Get
     * @return
     */
    public Object getCurrentElement() {
        return currElt;
    }
    
    /**
     * Iterate the list based on the direction.
     * Every iteration increments the number of steps
     * @return the current object of the list
     */
    public Object iterate() {
        Object obj =null;
        
        if ( direction == FORWARD ) {
            if ( !lit.hasNext() ) {
                lit =list.listIterator();
            } 
            
            obj =lit.next();
            
        } else if ( direction == BACKWARD ) {
            if ( !lit.hasPrevious() ) {
                lit =list.listIterator( list.size() - 1 );
            }
            
            obj =lit.previous();
        }
        
        currElt =obj;
        
        nbSteps++;
        
        return obj;
    }
    
    /**
     * Traverse the list looking for a specified element starting at the first element.
     * Direction is preserved.
     * Reset the step counter if it is found
     * @param obj 
     * @return true if the element was found, false otherwise
     */
    public boolean iterateUntil( Object obj ) {
        int dir =direction;
        reset();
        direction =dir;
        
        while( !hasTraversedAllElements() ) {
            if ( iterate().equals( obj ) ) {
                nbSteps =0;
                return true;
            }
        }

        return false;
    }
    
    /**
     * Reset the nb of steps
     * @see hasTraversedAllElements
     *
     */
    public void resetNbSteps() {
        nbSteps =0;
    }
    

}
